/*
 * pfo.h
 *
 * PFO .
 *
 * Copyright (C) 2022 Microwell, Inc.
 * Subject to the GNU Public License, version 2.
 *
 * Author: guoming<guoming@microwell.net>
 */
#ifndef _PFO_H_
#define _PFO_H_

#include "types.h"
#include "config.h"
#include "drive.h"
#include "mcu_regs.h"

// PFO frequency
#define FREQ_3300KHZ                    (3300000)      //3.3MHz
#define FREQ_3000KHZ                    (3000000)      //3.0MHz
#define FREQ_2400KHZ                    (2400000)      //2.4MHz
#define FREQ_1700KHZ                    (1700000)      //1.7MHz
#define FREQ_412KHZ                     (3300000/8)    //412.5KHz
#define FREQ_375KHZ                     (3000000/8)    //375KHz
#define FREQ_300KHZ                     (2400000/8)    //300KHz
#define FREQ_212KHZ                     (1700000/8)    //212.5KHz
#define FREQ_206KHZ                     (3300000/16)   //206.25KHz
#define FREQ_187KHZ                     (3000000/16)   //187.5KHz
#define FREQ_150KHZ                     (2400000/16)   //150KHz
#define FREQ_106KHZ                     (1700000/16)   //106.25KHz
#define FREQ_103KHZ                     (3300000/32)   //103.125KHz
#define FREQ_94KHZ                      (3000000/32)   //93.75KHz
#define FREQ_75KHZ                      (2400000/32)   //75KHz
#define FREQ_53KHZ                      (1700000/32)   //53.125KHz

/**************************** pfo config ********************************/

#define CONFIG_PFO_FREQ                 (FREQ_2400KHZ)

/***占空比调整只能在频率1.7MHz、2.4MHz、3MHz、3.3MHz, 且没有使能展频时有效**/
#define CONFIG_SPREAD_SPECTRUM          (RESET)
#define CONFIG_DUTY_ADJ_EN              (RESET)

/**************************** end ********************************/

#if (CONFIG_PFO_FREQ == FREQ_3300KHZ)
    #define CONFIG_PFO_CENTER_FREQ      (PRCFC_3300KHz)
    #define CONFIG_PFO_CENTER_DIV       (PRCDIV_1)
    #define CONFIG_DUTY_ADJ             (CONFIG_DUTY_ADJ_EN)
#elif (CONFIG_PFO_FREQ == FREQ_3000KHZ)
    #define CONFIG_PFO_CENTER_FREQ      (PRCFC_3000KHz)
    #define CONFIG_PFO_CENTER_DIV       (PRCDIV_1)
    #define CONFIG_DUTY_ADJ             (CONFIG_DUTY_ADJ_EN)
#elif (CONFIG_PFO_FREQ == FREQ_2400KHZ)
    #define CONFIG_PFO_CENTER_FREQ      (PRCFC_2400KHz)
    #define CONFIG_PFO_CENTER_DIV       (PRCDIV_1)
    #define CONFIG_DUTY_ADJ             (CONFIG_DUTY_ADJ_EN)
#elif (CONFIG_PFO_FREQ == FREQ_1700KHZ)
    #define CONFIG_PFO_CENTER_FREQ      (PRCFC_1700KHz)
    #define CONFIG_PFO_CENTER_DIV       (PRCDIV_1)
    #define CONFIG_DUTY_ADJ             (CONFIG_DUTY_ADJ_EN)
#elif (CONFIG_PFO_FREQ == FREQ_412KHZ)
    #define CONFIG_PFO_CENTER_FREQ      (PRCFC_3300KHz)
    #define CONFIG_PFO_CENTER_DIV       (PRCDIV_8)
    #define CONFIG_DUTY_ADJ             (RESET)
#elif (CONFIG_PFO_FREQ == FREQ_375KHZ)
    #define CONFIG_PFO_CENTER_FREQ      (PRCFC_3000KHz)
    #define CONFIG_PFO_CENTER_DIV       (PRCDIV_8)
    #define CONFIG_DUTY_ADJ             (RESET)
#elif (CONFIG_PFO_FREQ == FREQ_300KHZ)
    #define CONFIG_PFO_CENTER_FREQ      (PRCFC_2400KHz)
    #define CONFIG_PFO_CENTER_DIV       (PRCDIV_8)
    #define CONFIG_DUTY_ADJ             (RESET)
#elif (CONFIG_PFO_FREQ == FREQ_212KHZ)
    #define CONFIG_PFO_CENTER_FREQ      (PRCFC_1700KHz)
    #define CONFIG_PFO_CENTER_DIV       (PRCDIV_8)
    #define CONFIG_DUTY_ADJ             (RESET)
#elif (CONFIG_PFO_FREQ == FREQ_206KHZ)
    #define CONFIG_PFO_CENTER_FREQ      (PRCFC_3300KHz)
    #define CONFIG_PFO_CENTER_DIV       (PRCDIV_16)
    #define CONFIG_DUTY_ADJ             (RESET)
#elif (CONFIG_PFO_FREQ == FREQ_187KHZ)
    #define CONFIG_PFO_CENTER_FREQ      (PRCFC_3000KHz)
    #define CONFIG_PFO_CENTER_DIV       (PRCDIV_16)
    #define CONFIG_DUTY_ADJ             (RESET)
#elif (CONFIG_PFO_FREQ == FREQ_150KHZ)
    #define CONFIG_PFO_CENTER_FREQ      (PRCFC_2400KHz)
    #define CONFIG_PFO_CENTER_DIV       (PRCDIV_16)
    #define CONFIG_DUTY_ADJ             (RESET)
#elif (CONFIG_PFO_FREQ == FREQ_106KHZ)
    #define CONFIG_PFO_CENTER_FREQ      (PRCFC_1700KHz)
    #define CONFIG_PFO_CENTER_DIV       (PRCDIV_16)
    #define CONFIG_DUTY_ADJ             (RESET)
#elif (CONFIG_PFO_FREQ == FREQ_103KHZ)
    #define CONFIG_PFO_CENTER_FREQ      (PRCFC_3300KHz)
    #define CONFIG_PFO_CENTER_DIV       (PRCDIV_32)
    #define CONFIG_DUTY_ADJ             (RESET)
#elif (CONFIG_PFO_FREQ == FREQ_94KHZ)
    #define CONFIG_PFO_CENTER_FREQ      (PRCFC_3000KHz)
    #define CONFIG_PFO_CENTER_DIV       (PRCDIV_32)
    #define CONFIG_DUTY_ADJ             (RESET)
#elif (CONFIG_PFO_FREQ == FREQ_75KHZ)
    #define CONFIG_PFO_CENTER_FREQ      (PRCFC_2400KHz)
    #define CONFIG_PFO_CENTER_DIV       (PRCDIV_32)
    #define CONFIG_DUTY_ADJ             (RESET)
#elif (CONFIG_PFO_FREQ == FREQ_53KHZ)
    #define CONFIG_PFO_CENTER_FREQ      (PRCFC_1700KHz)
    #define CONFIG_PFO_CENTER_DIV       (PRCDIV_32)
    #define CONFIG_DUTY_ADJ             (RESET)
#endif

#ifndef CONFIG_PFO_CENTER_FREQ
#define CONFIG_PFO_CENTER_FREQ          (PRCFC_1700KHz)
#endif // !CONFIG_PFO_CENTER_FREQ

#ifndef CONFIG_PFO_CENTER_DIV
#define CONFIG_PFO_CENTER_DIV           (PRCDIV_1)
#endif // !CONFIG_PFO_CENTER_DIV

#ifndef CONFIG_DUTY_ADJ
#define CONFIG_DUTY_ADJ                 (RESET)
#endif // !CONFIG_DUTY_ADJ

enum pfo_duty_enum
{
    DUTY_6   = 0x00,
    DUTY_12  = 0x10,
    DUTY_19  = 0x20,
    DUTY_25  = 0x30,
    DUTY_31  = 0x40,
    DUTY_37  = 0x50,
    DUTY_44  = 0x60,
    DUTY_50  = 0x70,
    DUTY_56  = 0x80,
    DUTY_62  = 0x90,
    DUTY_69  = 0xA0,
    DUTY_75  = 0xB0,
    DUTY_81  = 0xC0,
    DUTY_87  = 0xD0,
    DUTY_94  = 0xE0,
    DUTY_100 = 0xF0,
};
#define MAX_PRC_FREQ                    (2047)
#define MIN_PRC_FREQ                    (0)
/**
 * @brief PFO寄存器宏定义
 * FPFO = (Fc + (Fc * 0.6 / 2048) * (PRCFREQ[10:0] - 1024)) / {1, 8, 16, 32}
 * PFO_ADJUST_STEPS_PRE_DIV = (Fc * 0.6 / 2048) / {1, 8, 16, 32}
 * 寄存器值转换成频率
 * PFO_REGVAL_TO_FREQ = (CONFIG_PFO_FREQ + PFO_ADJUST_STEPS_PRE_DIV * (PRCFREQ[10:0] - 1024))
 * 频率值转换成寄存器值
 * PFO_FREQ_TO_REGVAL = 1024 + (freq - CONFIG_PFO_FREQ) / PFO_ADJUST_STEPS_PRE_DIV
 */

#define PFO_ADJUST_STEPS_PRE_DIV        (ROUND_DIV(CONFIG_PFO_FREQ * 3 / 5, 2048))

#define PFO_REGVAL_TO_FREQ(regval)      (CONFIG_PFO_FREQ + ((PFO_ADJUST_STEPS_PRE_DIV * regval) - (PFO_ADJUST_STEPS_PRE_DIV * 1024)))
#define PFO_REGVAL_TO_FREQ_KHz(regval)  ((CONFIG_PFO_FREQ + ((PFO_ADJUST_STEPS_PRE_DIV * regval) - (PFO_ADJUST_STEPS_PRE_DIV * 1024))) / 1000)
#define PFO_FREQ_TO_REGVAL(freq)        (uint32_t)(1024 + ROUND_DIV((freq - CONFIG_PFO_FREQ), (PFO_ADJUST_STEPS_PRE_DIV)))
#define PFO_FREQ_MIN                    (uint32_t)PFO_REGVAL_TO_FREQ(MIN_PRC_FREQ)
#define PFO_FREQ_MAX                    (uint32_t)PFO_REGVAL_TO_FREQ(MAX_PRC_FREQ)

#if (GPIO_P07_PFO_MODE)
void pfo_init(void);
void pfo_exit(void);

void pfo_enable(void);
void pfo_disable(void);
/**
 * @brief 通过该接口设置PWM信号的频率
 * 
 * @param regval 这里的单位是PFO模块的寄存器值，不是Hz(0-2047)
 */
void pfo_set_freq(uint16_t regval);
void pfo_set_duty(enum pfo_duty_enum duty);
#else
#define pfo_init()
#define pfo_exit()

#define pfo_enable()
#define pfo_disable()
#define pfo_set_freq(regval)                (regval)
#define pfo_set_duty(duty)                  (duty)
#endif
#endif // !_PFO_H_